/**
 * 
 */
package jmath.function.meta;

import java.util.Date;
import java.math.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import cern.jet.random.engine.*;

/**
 * Class for presentation of interval on axis of values.
 * 
 * @author Timofei
 * 
 */
public class Interval {

	private Log log = LogFactory.getLog(Interval.class);

	private double lower;

	private double upper;

	private static final MersenneTwister64 random = new MersenneTwister64();

	private final Timer timer;

	private Random myRandom;

	private static class Timer {
		private Date date;

		public Timer() {
			date = new Date();
		}

		public long toc() {
			return new Date().getTime() - date.getTime();
		}
	}

	public static class Random {

		private double lower = 1.0;

		private double upper = 2.0;		

		public Random(double lower, double upper) {
			this.lower = lower;
			this.upper = upper;
		}

		public double getDouble() {
			double random = lower + (upper - lower) * Math.random();
			BigDecimal randomDecimal = new BigDecimal(random);
			int precision=getPrecision(lower, upper);
			//TODO:fix!!!
			if(lower<10 && upper>10 && random<10){
				precision=precision-1;
			}
			return randomDecimal.round(new MathContext(precision)).doubleValue();
		}

		private int getPrecision(double lower, double upper) {
			String lowerValue = prepare(lower + "");
			String upperValue = prepare(upper + "");
			while(lowerValue.endsWith("0") && upperValue.endsWith("0")){
				lowerValue=lowerValue.substring(0,lowerValue.length()-1);
				upperValue=upperValue.substring(0,upperValue.length()-1);
			}
			int lowerLength = lowerValue.length();			
			int upperLength = upperValue.length();		
			long difference = 0L;
			try {				
				difference = Long.parseLong(upperValue)-Long.parseLong(lowerValue);
			} catch (Exception ignored) {
			}
			if(difference==1L){
				return Math.max(lowerLength + 1, upperLength + 1);
			}
			return Math.max(lowerLength, upperLength);			
		}

		private String prepare(String stringValue) {
			String returnString = stringValue;			
			if (returnString.startsWith("0.")) {
				returnString = returnString.substring(2);
			}
			if (returnString.contains(".")) {
				returnString = returnString.replace(".","");
			}
			return returnString;
		}
	}

	public String toString() {
		return "[" + lower + "," + upper + "]";
	}

	public Interval(double lower, double upper) {
		this.lower = lower;
		this.upper = upper;
		timer = new Timer();
		myRandom = new Random(lower, upper);
	}

	public Double getLower() {
		return lower;
	}

	public Double getUpper() {
		return upper;
	}

	public void resizeInterval(double value) {
		if (value > upper) {
			upper = value;
		} else if (value < lower) {
			lower = value;
		}
		myRandom = new Random(lower, upper);
	}

	public boolean isInInterval(Double value) {
		return value >= lower && value <= upper;

	}

	public synchronized double getRandomValueOld() {
		if (upper == lower) {
			return lower;
		}
		double doubleRandom = 1.0 - ((((double) (timer.toc())) % 100.0) / 100.0);
		double twisterRandom = 1.0 - random.nextDouble() * random.nextDouble() * random.nextDouble()
				* random.nextDouble() * Math.random() * Math.random();

		doubleRandom = twisterRandom * doubleRandom;

		log.debug("random " + doubleRandom);

		double returnValue = lower + (upper - lower) * doubleRandom;

		return returnValue;
	}

	public synchronized double getRandomValue() {
		if (upper == lower) {
			return lower;
		}

		return myRandom.getDouble();
	}

	public boolean isWider(Interval interval) {
		return (upper - lower) > (interval.getUpper() - interval.getLower());
	}
}
